package service

import (
	"errors"
	"fmt"
	"strconv"
	"time"
	"wms/internal/model"
	"wms/internal/model/request"
	"wms/pkg/global"
	"wms/pkg/logger"
	"wms/pkg/utils"

	"go.uber.org/zap"
	"gorm.io/gorm"
)

// InventoryService 库存服务
type InventoryService struct {
	db     *gorm.DB
	logger *zap.Logger
	// notificationService *NotificationService
}

func NewInventoryService(db *gorm.DB, logger *zap.Logger) *InventoryService {
	return &InventoryService{
		db:     db,
		logger: logger,
		// notificationService: notificationService,
	}
}

// GetInventoryAlerts 获取库存预警列表
func (s *InventoryService) GetInventoryAlerts(req *request.ListInventoryAlertRequest) ([]*model.Inventory, int64, error) {
	var inventories []*model.Inventory
	var total int64

	db := global.DB.Model(&model.Inventory{}).
		Preload("Cargo").
		Preload("Warehouse").
		Preload("Location")

	// 添加查询条件
	if req.Keyword != "" {
		db = db.Joins("JOIN cargos p ON p.id = inventories.cargo_id").
			Where("p.code LIKE ? OR p.name LIKE ?", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
	}
	if req.WarehouseID != nil && *req.WarehouseID > 0 {
		db = db.Where("warehouse_id = ?", req.WarehouseID)
	}

	// 根据预警类型筛选
	switch req.AlertType {
	case 1: // 库存不足
		db = db.Joins("JOIN cargos p ON p.id = inventories.cargo_id").
			Where("inventories.quantity <= p.min_stock")
	case 2: // 库存积压
		db = db.Joins("JOIN cargos p ON p.id = inventories.cargo_id").
			Where("inventories.quantity >= p.max_stock")
	}

	// 获取总数
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 获取分页数据
	offset := (req.GetPage() - 1) * req.GetPageSize()
	if err := db.Offset(offset).Limit(req.GetPageSize()).Find(&inventories).Error; err != nil {
		return nil, 0, err
	}

	// --- 新增：强制重新加载关联数据 ---
	for _, inv := range inventories {
		if inv.CargoID > 0 && (inv.Cargo == nil || inv.Cargo.ID == 0) {
			s.logger.Warn("预加载 Cargo 失败，尝试手动加载", zap.Uint("inventoryID", inv.ID), zap.Uint("cargoID", inv.CargoID))
			var cargo model.Cargo
			if err := global.DB.Preload("Category").Preload("Supplier").First(&cargo, inv.CargoID).Error; err == nil {
				inv.Cargo = &cargo
			} else {
				s.logger.Error("手动加载 Cargo 失败", zap.Uint("inventoryID", inv.ID), zap.Uint("cargoID", inv.CargoID), zap.Error(err))
			}
		} else if inv.Cargo != nil {
			// 检查 Category 是否加载
			if inv.Cargo.CategoryID > 0 && inv.Cargo.Category.ID == 0 {
				s.logger.Warn("预加载 Cargo.Category 失败，尝试手动加载", zap.Uint("cargoID", inv.CargoID), zap.Uint("categoryID", inv.Cargo.CategoryID))
				var category model.CargoCategory
				if err := global.DB.First(&category, inv.Cargo.CategoryID).Error; err == nil {
					inv.Cargo.Category = category
				}
			}
			// 检查 Supplier 是否加载 (SupplierID 是指针)
			if inv.Cargo.SupplierID != nil && *inv.Cargo.SupplierID > 0 && inv.Cargo.Supplier == nil {
				s.logger.Warn("预加载 Cargo.Supplier 失败，尝试手动加载", zap.Uint("cargoID", inv.CargoID), zap.Uintp("supplierID", inv.Cargo.SupplierID))
				var supplier model.Supplier
				if err := global.DB.First(&supplier, *inv.Cargo.SupplierID).Error; err == nil {
					inv.Cargo.Supplier = &supplier
				}
			}
		}
	}
	// --- 结束新增代码 ---

	// --- 恢复手动加载循环，作为 Preload 的补充 ---
	// 恢复 Final Check 循环
	for _, inv := range inventories { // 取消注释
		// 增加检查 Cargo Name 是否为空，作为 Preload 失败的补充判断
		if inv.CargoID > 0 && (inv.Cargo == nil || inv.Cargo.ID == 0 || inv.Cargo.Name == "") {
			s.logger.Warn("(恢复后) Preload Cargo 可能失败或不完整，尝试手动加载", zap.Uint("inventoryID", inv.ID), zap.Uint("cargoID", inv.CargoID))
			var cargo model.Cargo
			// 手动加载时也预加载 Category 和 Supplier
			if err := global.DB.Preload("Category").Preload("Supplier").First(&cargo, inv.CargoID).Error; err == nil {
				inv.Cargo = &cargo
			} else {
				s.logger.Error("(恢复后) 手动加载 Cargo 失败", zap.Uint("inventoryID", inv.ID), zap.Uint("cargoID", inv.CargoID), zap.Error(err))
				// 如果手动加载失败，仍然创建一个空的 Cargo 对象并设置ID，避免后续 nil pointer，
				// 但保留 Category 和 Supplier 为 nil
				if inv.Cargo == nil {
					inv.Cargo = &model.Cargo{ID: inv.CargoID}
				}
			}
		}

		// 如果 Cargo 已加载，进一步检查 Category 和 Supplier 是否需要手动加载
		if inv.Cargo != nil {
			// 检查 Category
			// 修改：检查 Category ID 是否大于 0 并且 Category 结构体的 ID 是否为 0（未加载）
			if inv.Cargo.CategoryID > 0 && inv.Cargo.Category.ID == 0 {
				s.logger.Warn("(恢复后) Preload Cargo.Category 失败或未加载，尝试手动加载", zap.Uint("cargoID", inv.CargoID), zap.Uint("categoryID", inv.Cargo.CategoryID))
				var category model.CargoCategory
				if err := global.DB.First(&category, inv.Cargo.CategoryID).Error; err == nil {
					inv.Cargo.Category = category
				} else {
					s.logger.Error("(恢复后) 手动加载 Category 失败", zap.Uint("categoryID", inv.Cargo.CategoryID), zap.Error(err))
				}
			}
			// 检查 Supplier
			// 修改：检查 SupplierID 指针不为 nil 且 Supplier 指针为 nil (未加载)
			if inv.Cargo.SupplierID != nil && *inv.Cargo.SupplierID > 0 && inv.Cargo.Supplier == nil {
				s.logger.Warn("(恢复后) Preload Cargo.Supplier 失败或未加载，尝试手动加载", zap.Uint("cargoID", inv.CargoID), zap.Uintp("supplierID", inv.Cargo.SupplierID))
				var supplier model.Supplier
				if err := global.DB.First(&supplier, *inv.Cargo.SupplierID).Error; err == nil {
					inv.Cargo.Supplier = &supplier
				} else {
					s.logger.Error("(恢复后) 手动加载 Supplier 失败", zap.Uintp("supplierID", inv.Cargo.SupplierID), zap.Error(err))
				}
			}
		}
	} // 添加循环的结束括号
	// --- 结束恢复 ---

	// 加载批次信息 (保持不变)
	if err := s.loadBatchInfoForInventories(inventories); err != nil {
		s.logger.Warn("(恢复后) 加载批次信息失败，将使用备用方法", zap.Error(err)) // 修改 logger 为 s.logger
		s.loadBatchInfoFallback(inventories)
	}

	return inventories, total, nil
}

// GetInventoryAlertCount 获取库存预警数量
func (s *InventoryService) GetInventoryAlertCount() (map[string]int64, error) {
	var insufficientCount, excessiveCount int64

	// 统计库存不足数量
	if err := global.DB.Model(&model.Inventory{}).
		Joins("JOIN cargos p ON p.id = inventories.cargo_id").
		Where("inventories.quantity <= p.min_stock").
		Count(&insufficientCount).Error; err != nil {
		return nil, err
	}

	// 统计库存积压数量
	if err := global.DB.Model(&model.Inventory{}).
		Joins("JOIN cargos p ON p.id = inventories.cargo_id").
		Where("inventories.quantity >= p.max_stock").
		Count(&excessiveCount).Error; err != nil {
		return nil, err
	}

	return map[string]int64{
		"insufficient": insufficientCount,
		"excessive":    excessiveCount,
	}, nil
}

// CreateInventoryCheck 创建库存盘点单
func (s *InventoryService) CreateInventoryCheck(req *request.InventoryCheckCreateRequest, userID uint) (*model.InventoryCheck, error) {
	// 开启事务
	check := &model.InventoryCheck{
		Code:        utils.GenerateOrderNo("IC"),
		WarehouseID: req.WarehouseID,
		Status:      1,
		UserID:      userID,
		Note:        req.Note,
	}

	return check, global.DB.Transaction(func(tx *gorm.DB) error {
		// 创建盘点单
		if err := tx.Create(check).Error; err != nil {
			return err
		}

		// 获取仓库下所有库存记录
		var inventories []model.Inventory
		if err := tx.Where("warehouse_id = ?", req.WarehouseID).Find(&inventories).Error; err != nil {
			return err
		}

		// 创建盘点货物记录
		for _, inv := range inventories {
			item := &model.InventoryCheckItem{
				InventoryCheckID: check.ID,
				CargoID:          inv.CargoID,
				LocationID:       inv.LocationID,
				BookQty:          inv.Quantity,
				CheckQty:         0,
				DiffQty:          0,
				Status:           1,
			}
			if err := tx.Create(item).Error; err != nil {
				return err
			}
		}

		return nil
	})
}

// CompleteInventoryCheck 完成库存盘点
func (s *InventoryService) CompleteInventoryCheck(id uint, req *request.CompleteInventoryCheckRequest, userID uint) error {
	// 检查盘点单是否存在
	var check model.InventoryCheck
	if err := global.DB.First(&check, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("盘点单不存在")
		}
		return err
	}

	// 检查盘点单状态
	if check.Status == 2 {
		return errors.New("盘点单已完成")
	}

	// 开启事务
	return global.DB.Transaction(func(tx *gorm.DB) error {
		// 更新盘点货物记录
		for _, p := range req.Products {
			// 更新盘点货物记录
			updates := map[string]interface{}{
				"check_qty": p.ActualQty,
				"diff_qty":  p.DifferenceQty,
				"status":    2,
				"note":      p.Remark,
			}

			if err := tx.Model(&model.InventoryCheckItem{}).
				Where("inventory_check_id = ? AND cargo_id = ? AND location_id = ?", check.ID, p.CargoID, p.LocationID).
				Updates(updates).Error; err != nil {
				return err
			}

			// 获取更新前的库存量，用于记录日志
			var inventoryBefore model.Inventory
			if err := tx.Where("cargo_id = ? AND location_id = ?", p.CargoID, p.LocationID).First(&inventoryBefore).Error; err != nil {
				// 如果盘点前库存记录不存在，可能是一个问题，但这里先假设它存在或允许盘点时创建
				s.logger.Warn("查找盘点前库存记录失败，可能影响日志记录", zap.Uint("cargoID", p.CargoID), zap.Uint("locationID", p.LocationID), zap.Error(err))
				// 即使找不到旧记录，也尝试更新或创建，让盘点流程继续
			}
			beforeStock := inventoryBefore.Quantity // Get quantity before update

			// 更新实际库存数量 (使用 Updates 而不是 Update 来处理零值)
			if err := tx.Model(&model.Inventory{}).
				Where("cargo_id = ? AND location_id = ?", p.CargoID, p.LocationID).
				Updates(map[string]interface{}{"quantity": p.ActualQty}).Error; err != nil {
				// Consider using FirstOrCreate or similar if inventory might not exist
				return err
			}

			// 添加库存日志记录
			// 计算实际变动量
			adjustQuantity := p.ActualQty - beforeStock
			if adjustQuantity != 0 { // 只记录实际发生变动的
				log := &model.InventoryLog{
					CargoID:     p.CargoID,
					WarehouseID: check.WarehouseID, // 从盘点单获取仓库ID
					LocationID:  p.LocationID,
					Type:        "check", // 新增类型 "check"
					Quantity:    int(adjustQuantity),
					BeforeStock: int(beforeStock),
					AfterStock:  int(p.ActualQty),
					OrderType:   "inventory_check", // 关联单据类型
					OrderID:     check.ID,          // 关联盘点单ID
					OperatorID:  userID,
					Remark:      fmt.Sprintf("盘点调整: %s", p.Remark), // 添加备注
				}
				if err := tx.Create(log).Error; err != nil {
					s.logger.Error("创建盘点库存日志失败", zap.Error(err))
					return errors.New("记录库存日志失败")
				}
			}
		}

		// 更新盘点单状态
		return tx.Model(&check).Updates(map[string]interface{}{
			"status":           2,
			"complete_time":    time.Now(),
			"complete_user_id": userID,
		}).Error
	})
}

// GetInventoryCheckByID 获取库存盘点单详情
func (s *InventoryService) GetInventoryCheckByID(id uint) (*model.InventoryCheck, error) {
	var check model.InventoryCheck
	if err := global.DB.Preload("Warehouse").
		Preload("Items").
		Preload("Items.Cargo").
		Preload("Items.Location").
		First(&check, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("盘点单不存在")
		}
		return nil, err
	}
	return &check, nil
}

// ListInventoryCheck 获取库存盘点单列表
func (s *InventoryService) ListInventoryCheck(req *request.InventoryCheckListRequest) ([]*model.InventoryCheck, int64, error) {
	var checks []*model.InventoryCheck
	var total int64

	db := global.DB.Model(&model.InventoryCheck{}).
		Preload("Warehouse")

	// 添加查询条件
	if req.Keyword != "" {
		db = db.Where("code LIKE ?", "%"+req.Keyword+"%")
	}
	if req.WarehouseID != nil && *req.WarehouseID > 0 {
		db = db.Where("warehouse_id = ?", req.WarehouseID)
	}
	if req.Status != nil && *req.Status > 0 {
		db = db.Where("status = ?", req.Status)
	}
	if req.StartTime != "" {
		db = db.Where("created_at >= ?", req.StartTime)
	}
	if req.EndTime != "" {
		db = db.Where("created_at <= ?", req.EndTime)
	}

	// 获取总数
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 获取分页数据
	offset := (req.GetPage() - 1) * req.GetPageSize()
	if err := db.Offset(offset).Limit(req.GetPageSize()).Find(&checks).Error; err != nil {
		return nil, 0, err
	}

	return checks, total, nil
}

// UpdateInbound 更新入库单
func (s *InventoryService) UpdateInbound(id uint, req *request.InboundUpdateRequest, userID uint) error {
	// 检查入库单是否存在
	var inbound model.InboundOrder
	if err := global.DB.First(&inbound, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("入库单不存在")
		}
		return err
	}

	// 检查入库单状态
	if inbound.Status != 1 {
		return errors.New("只能修改待审核的入库单")
	}

	// 检查仓库是否存在
	var warehouse model.Warehouse
	if err := global.DB.First(&warehouse, req.WarehouseID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("仓库不存在")
		}
		return err
	}

	// 如果有供应商ID，检查供应商是否存在
	if req.SupplierID != nil {
		var supplier model.Supplier
		if err := global.DB.First(&supplier, req.SupplierID).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return errors.New("供应商不存在")
			}
			return err
		}
	}

	// 开启事务
	return global.DB.Transaction(func(tx *gorm.DB) error {
		// 更新入库单主信息
		inbound.WarehouseID = req.WarehouseID
		inbound.SupplierID = req.SupplierID
		inbound.OrderNo = req.OrderNo
		inbound.Note = req.Note
		inbound.Type = req.Type
		inbound.UserID = userID

		// 更新入库单信息
		if err := tx.Model(&inbound).Updates(map[string]interface{}{
			"warehouse_id": req.WarehouseID,
			"supplier_id":  req.SupplierID,
			"notes":        req.Notes,
			"updated_by":   userID,
		}).Error; err != nil {
			return err
		}

		// 删除旧的入库明细
		if err := tx.Where("inbound_id = ?", id).Delete(&model.InboundOrderItem{}).Error; err != nil {
			return err
		}

		// 创建新的入库明细
		for _, itemReq := range req.Items {
			item := model.InboundOrderItem{
				InboundOrderID: id,
				CargoID:        itemReq.CargoID,
				Quantity:       itemReq.Quantity,
				UnitPrice:      itemReq.UnitPrice,
				Note:           itemReq.Note,
			}
			if err := tx.Create(&item).Error; err != nil {
				s.logger.Error("创建入库明细失败", zap.Uint("cargoID", itemReq.CargoID), zap.Error(err))
				return errors.New("创建入库明细失败")
			}
		}

		return nil
	})
}

// ListInventory 获取库存列表
func (s *InventoryService) ListInventory(req *request.InventoryListRequest) ([]*model.Inventory, int64, error) {
	var inventories []*model.Inventory
	var total int64

	// 构建查询
	db := s.db.Model(&model.Inventory{})

	// 预加载关联数据 - 确保正确预加载Cargo及其关联关系
	db = db.Preload("Cargo").
		Preload("Cargo.Category"). // 明确预加载Category关系
		Preload("Cargo.Supplier"). // 明确预加载Supplier关系
		Preload("Warehouse").
		Preload("Location")

	// 添加过滤条件
	if req.Keyword != "" {
		db = db.Joins("JOIN cargos c ON c.id = inventories.cargo_id").
			Where("c.name LIKE ? OR c.code LIKE ?", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
	}
	if req.WarehouseID > 0 {
		db = db.Where("warehouse_id = ?", req.WarehouseID)
	}
	if req.CargoCode != "" {
		db = db.Joins("JOIN cargos c ON c.id = inventories.cargo_id").
			Where("c.code LIKE ?", "%"+req.CargoCode+"%")
	}
	if req.LocationID > 0 {
		db = db.Where("location_id = ?", req.LocationID)
	}
	if req.Status != nil && *req.Status > 0 {
		db = db.Where("inventories.status = ?", *req.Status)
	}
	if req.CargoID != nil && *req.CargoID > 0 {
		db = db.Where("inventories.cargo_id = ?", *req.CargoID)
	}
	if req.BatchNo != "" {
		db = db.Joins("JOIN inventory_batches b ON b.inventory_id = inventories.id").
			Where("b.batch_no LIKE ?", "%"+req.BatchNo+"%")
	}

	// 添加排序
	if req.SortBy != "" {
		sortDir := "ASC"
		if req.SortOrder == "desc" {
			sortDir = "DESC"
		}

		switch req.SortBy {
		case "quantity":
			db = db.Order("quantity " + sortDir)
		case "cargo_name":
			db = db.Joins("JOIN cargos c ON c.id = inventories.cargo_id").
				Order("c.name " + sortDir)
		case "updated_at":
			db = db.Order("updated_at " + sortDir)
		default:
			db = db.Order("id " + sortDir)
		}
	} else {
		// 默认排序
		db = db.Order("id ASC")
	}

	// 获取总数
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 获取分页数据
	offset := (req.GetPage() - 1) * req.GetPageSize()
	if err := db.Offset(offset).Limit(req.GetPageSize()).Find(&inventories).Error; err != nil {
		return nil, 0, err
	}

	// 加载批次信息
	if err := s.loadBatchInfoForInventories(inventories); err != nil {
		s.logger.Warn("加载批次信息失败，将使用备用方法", zap.Error(err))
		s.loadBatchInfoFallback(inventories)
	}

	// 填充平铺字段，方便前端显示
	for _, inv := range inventories {
		if inv.Cargo != nil {
			inv.CargoCode = inv.Cargo.Code
			inv.CargoName = inv.Cargo.Name
			inv.Unit = inv.Cargo.Unit

			// 填充分类信息
			if inv.Cargo.Category.ID > 0 {
				// 检查 Category 是否正确加载（名称不为空）
				if inv.Cargo.Category.Name != "" {
					inv.CategoryName = inv.Cargo.Category.Name
				} else {
					// 分类信息不完整，尝试手动加载
					s.logger.Warn("分类名称为空，尝试手动加载",
						zap.Uint("cargoID", inv.Cargo.ID),
						zap.Uint("categoryID", inv.Cargo.CategoryID))

					var category model.CargoCategory
					if err := s.db.First(&category, inv.Cargo.CategoryID).Error; err == nil {
						inv.CategoryName = category.Name
						// 更新 Cargo 对象中的 Category，避免后续再次查询
						inv.Cargo.Category = category
					} else {
						s.logger.Error("手动加载分类失败",
							zap.Uint("categoryID", inv.Cargo.CategoryID),
							zap.Error(err))
					}
				}
			}

			// 填充供应商信息
			if inv.Cargo.Supplier != nil && inv.Cargo.Supplier.ID > 0 {
				if inv.Cargo.Supplier.Name != "" {
					inv.SupplierName = inv.Cargo.Supplier.Name
				} else {
					// 供应商信息不完整，尝试手动加载
					s.logger.Warn("供应商名称为空，尝试手动加载",
						zap.Uint("cargoID", inv.Cargo.ID),
						zap.Uintp("supplierID", inv.Cargo.SupplierID))

					var supplier model.Supplier
					if err := s.db.First(&supplier, *inv.Cargo.SupplierID).Error; err == nil {
						inv.SupplierName = supplier.Name
						// 更新 Cargo 对象中的 Supplier
						inv.Cargo.Supplier = &supplier
					} else {
						s.logger.Error("手动加载供应商失败",
							zap.Uintp("supplierID", inv.Cargo.SupplierID),
							zap.Error(err))
					}
				}
			}
		}

		// 填充仓库信息
		if inv.Warehouse != nil {
			inv.WarehouseName = inv.Warehouse.Name
		}

		// 填充库位信息
		if inv.Location != nil {
			inv.LocationCode = inv.Location.Code
		}
	}

	return inventories, total, nil
}

// GetInventoryStatus 获取库存状态
func (s *InventoryService) GetInventoryStatus(cargoID uint) (*model.InventoryStatus, error) {
	var totalQty, lockedQty float64

	// 1. Get total physical quantity
	err := global.DB.Model(&model.Inventory{}).
		Where("cargo_id = ?", cargoID).
		Select("COALESCE(SUM(quantity), 0)").
		Row().Scan(&totalQty)
	if err != nil {
		s.logger.Error("获取总库存失败", zap.Uint("cargo_id", cargoID), zap.Error(err))
		return nil, errors.New("获取总库存失败")
	}

	// 2. Get locked quantity (Example: sum quantity from pending outbound items)
	err = global.DB.Model(&model.OutboundOrderItem{}).
		Joins("JOIN outbound_orders oo ON oo.id = outbound_order_items.order_id").
		Where("oo.status = ?", "pending"). // Needs correct status value
		Where("outbound_order_items.cargo_id = ?", cargoID).
		Select("COALESCE(SUM(outbound_order_items.quantity), 0)").
		Row().Scan(&lockedQty)
	if err != nil {
		s.logger.Error("获取锁定库存失败", zap.Uint("cargo_id", cargoID), zap.Error(err))
		lockedQty = 0
	}

	// 3. Get Cargo Name
	var cargo model.Cargo
	if err = global.DB.Select("name").First(&cargo, cargoID).Error; err != nil {
		s.logger.Warn("获取货物名称失败", zap.Uint("cargo_id", cargoID), zap.Error(err))
	}

	status := &model.InventoryStatus{
		CargoID:       cargoID,
		CargoName:     cargo.Name,
		TotalQuantity: totalQty,
		LockedQty:     lockedQty,
		AvailableQty:  totalQty - lockedQty,
	}

	return status, nil
}

// SetInventoryAlert 设置库存预警
func (s *InventoryService) SetInventoryAlert(req *request.InventoryAlertRequest) error {
	// 检查货物是否存在 (Corrected model)
	var cargo model.Cargo                                         // Use Cargo model
	if err := s.db.First(&cargo, req.CargoID).Error; err != nil { // Use CargoID
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("货物不存在")
		}
		return err
	}

	// 更新货物的预警设置
	updates := map[string]interface{}{}

	if req.MinStock != nil && *req.MinStock >= 0 {
		updates["min_stock"] = req.MinStock
	}
	if req.MaxStock != nil && *req.MaxStock >= 0 {
		updates["max_stock"] = req.MaxStock
	}

	return s.db.Model(&cargo).Updates(updates).Error
}

// GetInventory 获取库存详情
func (s *InventoryService) GetInventory(id uint) (*model.Inventory, error) {
	var inventory model.Inventory

	err := s.db.Preload("Cargo").
		Preload("Cargo.Category").
		Preload("Cargo.Supplier").
		Preload("Warehouse").
		Preload("Location").
		First(&inventory, id).Error

	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("库存记录不存在")
		}
		return nil, err
	}

	// 加载批次信息
	if err := s.loadBatchInfoForInventories([]*model.Inventory{&inventory}); err != nil {
		s.logger.Warn("加载批次信息失败，将使用备用方法", zap.Error(err))
		s.loadBatchInfoFallback([]*model.Inventory{&inventory})
	}

	// 填充平铺字段，方便前端显示
	if inventory.Cargo != nil {
		inventory.CargoCode = inventory.Cargo.Code
		inventory.CargoName = inventory.Cargo.Name
		inventory.Unit = inventory.Cargo.Unit

		// 填充分类信息
		if inventory.Cargo.Category.ID > 0 {
			inventory.CategoryName = inventory.Cargo.Category.Name
		}
	}

	// 填充仓库信息
	if inventory.Warehouse != nil {
		inventory.WarehouseName = inventory.Warehouse.Name
	}

	// 填充库位信息
	if inventory.Location != nil {
		inventory.LocationCode = inventory.Location.Code
	}

	return &inventory, nil
}

// AdjustInventory 调整库存
func (s *InventoryService) AdjustInventory(req *request.InventoryAdjustRequest, userID uint) error {
	// 检查库存记录是否存在
	var inventory model.Inventory
	if err := s.db.Where("cargo_id = ? AND location_id = ?", req.CargoID, req.LocationID).First(&inventory).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("库存记录不存在")
		}
		return err
	}

	// 计算调整前后的库存
	beforeStock := inventory.Quantity
	afterStock := beforeStock + req.AdjustQuantity

	// 开启事务处理库存调整和日志记录
	return s.db.Transaction(func(tx *gorm.DB) error {
		// 更新库存数量
		if err := tx.Model(&inventory).Update("quantity", afterStock).Error; err != nil {
			return errors.New("更新库存失败")
		}

		// 创建库存日志
		log := &model.InventoryLog{
			CargoID:     req.CargoID,
			WarehouseID: inventory.WarehouseID,
			LocationID:  req.LocationID,
			Type:        "adjust",
			Quantity:    int(req.AdjustQuantity),
			BeforeStock: int(beforeStock),
			AfterStock:  int(afterStock),
			OrderType:   "adjustment",
			OrderID:     0, // 手动调整没有关联订单
			OperatorID:  userID,
			Remark:      req.Remark,
		}

		if err := tx.Create(log).Error; err != nil {
			return errors.New("记录库存日志失败")
		}

		// 使用优化后的LogOperation记录操作日志，方便前端展示
		operationDetails := fmt.Sprintf("库存调整 - 货物ID:%d, 调整数量:%.2f, 调整前:%.2f, 调整后:%.2f",
			req.CargoID, req.AdjustQuantity, beforeStock, afterStock)
		logger.LogOperation("库存调整", userID, operationDetails)

		return nil
	})
}

// CreateInbound 创建入库单
func (s *InventoryService) CreateInbound(req *request.InboundCreateRequest, userID uint) (*model.InboundOrder, error) {
	// 检查仓库是否存在
	var warehouse model.Warehouse
	if err := s.db.First(&warehouse, req.WarehouseID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("仓库不存在")
		}
		return nil, err
	}

	// 如果有供应商ID，检查供应商是否存在
	if req.SupplierID != nil && *req.SupplierID > 0 {
		var supplier model.Supplier
		if err := s.db.First(&supplier, *req.SupplierID).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, errors.New("供应商不存在")
			}
			return nil, err
		}
	}

	// 创建入库单
	now := time.Now()
	inbound := &model.InboundOrder{
		Code:         utils.GenerateOrderNo("IN"),
		Type:         req.Type,
		WarehouseID:  req.WarehouseID,
		SupplierID:   req.SupplierID,
		ExpectedTime: req.ExpectedTime,
		OrderNo:      req.OrderNo,
		Note:         req.Notes,                         // 使用 Notes 字段作为备注
		Status:       model.StatusInboundWaitingReceive, // 创建时默认为待收货(1)
		UserID:       userID,
		CreatedAt:    now,
		UpdatedAt:    now,
	}

	// 开启事务
	err := s.db.Transaction(func(tx *gorm.DB) error {
		// 创建入库单
		if err := tx.Create(inbound).Error; err != nil {
			return err
		}

		// 创建入库明细
		for _, itemReq := range req.Items {
			// 检查货物是否存在
			var cargo model.Cargo
			if err := tx.First(&cargo, itemReq.CargoID).Error; err != nil {
				if errors.Is(err, gorm.ErrRecordNotFound) {
					return fmt.Errorf("货物ID %d 不存在", itemReq.CargoID)
				}
				return err
			}

			item := model.InboundOrderItem{
				InboundOrderID: inbound.ID,
				CargoID:        itemReq.CargoID,
				Quantity:       itemReq.Quantity,
				UnitPrice:      itemReq.UnitPrice,
				Note:           itemReq.Note,
			}

			if err := tx.Create(&item).Error; err != nil {
				return err
			}
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	// 记录入库单创建成功的日志
	s.logger.Info("入库单创建成功",
		zap.String("code", inbound.Code),
		zap.Uint("id", inbound.ID),
		zap.Int("type", inbound.Type),
		zap.Uint("warehouseID", inbound.WarehouseID),
		zap.Uintp("supplierID", inbound.SupplierID),
		zap.Uint("userID", userID),
		zap.Int("itemCount", len(req.Items)))

	return inbound, nil
}

// CreateOutbound 创建出库单
func (s *InventoryService) CreateOutbound(req *request.OutboundCreateRequest, userID uint) (*model.OutboundOrder, error) {
	// 检查仓库是否存在
	var warehouse model.Warehouse
	if err := s.db.First(&warehouse, req.WarehouseID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("仓库不存在")
		}
		return nil, err
	}

	// 如果有客户ID，检查客户是否存在
	if req.CustomerID != nil && *req.CustomerID > 0 {
		var customer model.Customer
		if err := s.db.First(&customer, *req.CustomerID).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, errors.New("客户不存在")
			}
			return nil, err
		}
	}

	// 创建出库单
	outbound := &model.OutboundOrder{
		Code:        utils.GenerateOrderNo("OUT"),
		WarehouseID: req.WarehouseID,
		CustomerID:  req.CustomerID,
		OrderNo:     req.OrderNo,
		Type:        req.Type,
		Status:      1, // 待审核
		UserID:      userID,
		Note:        req.Notes, // 修正 Notes 为 Note
	}

	// 开启事务
	err := s.db.Transaction(func(tx *gorm.DB) error {
		// 创建出库单
		if err := tx.Create(outbound).Error; err != nil {
			return err
		}

		// 创建出库明细
		for _, itemReq := range req.Items {
			// 检查货物是否存在
			var cargo model.Cargo
			if err := tx.First(&cargo, itemReq.CargoID).Error; err != nil {
				if errors.Is(err, gorm.ErrRecordNotFound) {
					return fmt.Errorf("货物ID %d 不存在", itemReq.CargoID)
				}
				return err
			}

			// 检查库存是否足够
			var totalStock float64
			if err := tx.Model(&model.Inventory{}).
				Where("cargo_id = ? AND warehouse_id = ?", itemReq.CargoID, req.WarehouseID).
				Select("COALESCE(SUM(quantity), 0)").
				Row().Scan(&totalStock); err != nil {
				return err
			}

			if totalStock < itemReq.Quantity {
				return fmt.Errorf("货物 %s 库存不足，当前库存 %.2f，需要 %.2f",
					cargo.Name, totalStock, itemReq.Quantity)
			}

			item := model.OutboundOrderItem{
				OutboundOrderID: outbound.ID,
				CargoID:         itemReq.CargoID,
				Quantity:        itemReq.Quantity,
				UnitPrice:       itemReq.UnitPrice,
				Note:            itemReq.Note,
			}

			if err := tx.Create(&item).Error; err != nil {
				return err
			}
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	// 记录出库单创建成功的日志
	s.logger.Info("出库单创建成功",
		zap.String("code", outbound.Code),
		zap.Uint("id", outbound.ID),
		zap.Int("type", outbound.Type),
		zap.Uint("warehouseID", outbound.WarehouseID),
		zap.Uintp("customerID", outbound.CustomerID),
		zap.Uint("userID", userID),
		zap.Int("itemCount", len(req.Items)))

	return outbound, nil
}

// GetOutboundByID 获取出库单详情
func (s *InventoryService) GetOutboundByID(id uint) (*model.OutboundOrder, error) {
	var outbound model.OutboundOrder
	if err := s.db.Preload("Items").
		Preload("Items.Cargo").
		Preload("Warehouse").
		Preload("Customer").
		Preload("User").
		Preload("ApproveUser").
		First(&outbound, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("出库单不存在")
		}
		return nil, err
	}
	return &outbound, nil
}

// ListOutbound 获取出库单列表
func (s *InventoryService) ListOutbound(req *request.OutboundListRequest) ([]*model.OutboundOrder, int64, error) {
	var outbounds []*model.OutboundOrder
	var total int64

	db := s.db.Model(&model.OutboundOrder{}).
		Preload("Items").
		Preload("Items.Cargo").
		Preload("Warehouse").
		Preload("Customer").
		Preload("User").
		Preload("ApproveUser")

	// 添加查询条件
	if req.Keyword != "" {
		db = db.Where("code LIKE ? OR order_no LIKE ?", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
	}
	if req.WarehouseID > 0 {
		db = db.Where("warehouse_id = ?", req.WarehouseID)
	}
	if req.Status > 0 {
		db = db.Where("status = ?", req.Status)
	}
	if req.StartTime != "" {
		db = db.Where("created_at >= ?", req.StartTime)
	}
	if req.EndTime != "" {
		db = db.Where("created_at <= ?", req.EndTime)
	}

	// 获取总数
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 获取分页数据
	offset := (req.GetPage() - 1) * req.GetPageSize()
	if err := db.Offset(offset).Limit(req.GetPageSize()).Find(&outbounds).Error; err != nil {
		return nil, 0, err
	}

	return outbounds, total, nil
}

// UpdateOutbound 更新出库单
func (s *InventoryService) UpdateOutbound(id uint, req *request.OutboundUpdateRequest, userID uint) error {
	// 检查出库单是否存在
	var outbound model.OutboundOrder
	if err := s.db.First(&outbound, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("出库单不存在")
		}
		return err
	}

	// 检查出库单状态
	if outbound.Status != 1 {
		return errors.New("只能修改待审核的出库单")
	}

	// 检查仓库是否存在
	var warehouse model.Warehouse
	if err := s.db.First(&warehouse, req.WarehouseID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("仓库不存在")
		}
		return err
	}

	// 如果有客户ID，检查客户是否存在
	if req.CustomerID != nil {
		var customer model.Customer
		if err := s.db.First(&customer, req.CustomerID).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return errors.New("客户不存在")
			}
			return err
		}
	}

	// 开启事务
	return s.db.Transaction(func(tx *gorm.DB) error {
		// 更新出库单主信息
		updates := map[string]interface{}{
			"warehouse_id": req.WarehouseID,
			"customer_id":  req.CustomerID,
			"order_no":     req.OrderNo,
			"type":         req.Type,
			"notes":        req.Notes,
			"updated_by":   userID,
		}

		if err := tx.Model(&outbound).Updates(updates).Error; err != nil {
			return err
		}

		// 删除旧的出库明细
		if err := tx.Where("outbound_order_id = ?", id).Delete(&model.OutboundOrderItem{}).Error; err != nil {
			return err
		}

		// 创建新的出库明细
		for _, itemReq := range req.Items {
			// 检查货物是否存在
			var cargo model.Cargo
			if err := tx.First(&cargo, itemReq.CargoID).Error; err != nil {
				if errors.Is(err, gorm.ErrRecordNotFound) {
					return fmt.Errorf("货物ID %d 不存在", itemReq.CargoID)
				}
				return err
			}

			// 检查库存是否足够
			var totalStock float64
			if err := tx.Model(&model.Inventory{}).
				Where("cargo_id = ? AND warehouse_id = ?", itemReq.CargoID, req.WarehouseID).
				Select("COALESCE(SUM(quantity), 0)").
				Row().Scan(&totalStock); err != nil {
				return err
			}

			if totalStock < itemReq.Quantity {
				return fmt.Errorf("货物 %s 库存不足，当前库存 %.2f，需要 %.2f",
					cargo.Name, totalStock, itemReq.Quantity)
			}

			item := model.OutboundOrderItem{
				OutboundOrderID: id,
				CargoID:         itemReq.CargoID,
				Quantity:        itemReq.Quantity,
				UnitPrice:       itemReq.UnitPrice,
				Note:            itemReq.Note,
			}

			if err := tx.Create(&item).Error; err != nil {
				return err
			}
		}

		return nil
	})
}

// PickOrder 处理拣货操作
func (s *InventoryService) PickOrder(orderID uint, req *request.PickRequest, userID uint) error {
	var outbound model.OutboundOrder
	// 预加载 Items 以便更新明细
	if err := s.db.Preload("Items").
		Preload("Items.Cargo").
		Preload("Warehouse").
		First(&outbound, orderID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("出库单不存在")
		}
		return err
	}

	// 检查状态是否为待拣货
	if outbound.Status != model.StatusOutboundWaitingPicking { // 修正常量名
		return errors.New("出库单状态不是待拣货")
	}

	// 检查请求中的明细是否与订单匹配
	orderItemMap := make(map[uint]*model.OutboundOrderItem)
	for _, item := range outbound.Items {
		orderItemMap[item.ID] = item
	}

	// 开启事务
	return s.db.Transaction(func(tx *gorm.DB) error {
		now := time.Now()

		// 更新拣货明细信息并扣减库存
		for _, reqItem := range req.Items {
			// 获取订单明细项
			orderItem, ok := orderItemMap[reqItem.OrderItemID]
			if !ok {
				return fmt.Errorf("请求中包含无效的出库单明细ID: %d", reqItem.OrderItemID)
			}

			// 检查拣货数量是否合法
			if reqItem.PickedQuantity <= 0 {
				return errors.New("拣货数量必须大于0")
			}
			if reqItem.PickedQuantity > orderItem.Quantity {
				return fmt.Errorf("拣货数量 %.2f 超过订单数量 %.2f", reqItem.PickedQuantity, orderItem.Quantity)
			}

			// 检查库位是否存在且有效
			var location model.Location
			if err := tx.Where("id = ? AND status = ?", reqItem.LocationID, 1).First(&location).Error; err != nil {
				if errors.Is(err, gorm.ErrRecordNotFound) {
					return fmt.Errorf("指定的库位无效或不存在: %d", reqItem.LocationID)
				}
				return err
			}

			// 获取库存记录
			var inventory model.Inventory
			if err := tx.Where("cargo_id = ? AND location_id = ?", orderItem.CargoID, reqItem.LocationID).First(&inventory).Error; err != nil {
				if errors.Is(err, gorm.ErrRecordNotFound) {
					return fmt.Errorf("库位 %s 没有货物 %d 的库存记录", location.Code, orderItem.CargoID)
				}
				return err
			}

			// 检查库存是否足够
			if inventory.Quantity < reqItem.PickedQuantity {
				return fmt.Errorf("库位 %s 货物 %s 库存不足，当前库存 %.2f，需要 %.2f",
					location.Code, orderItem.Cargo.Name, inventory.Quantity, reqItem.PickedQuantity)
			}

			// 扣减库存
			beforeStock := inventory.Quantity
			afterStock := beforeStock - reqItem.PickedQuantity
			if err := tx.Model(&inventory).Update("quantity", afterStock).Error; err != nil {
				return errors.New("更新库存失败")
			}

			// 创建库存日志
			log := &model.InventoryLog{
				CargoID:     orderItem.CargoID,
				WarehouseID: outbound.WarehouseID,
				LocationID:  reqItem.LocationID,
				Type:        "out",
				Quantity:    -int(reqItem.PickedQuantity),
				BeforeStock: int(beforeStock),
				AfterStock:  int(afterStock),
				OrderType:   "outbound",
				OrderID:     outbound.ID,
				OperatorID:  userID,
				Remark:      "出库单拣货",
			}
			if err := tx.Create(log).Error; err != nil {
				return errors.New("记录库存日志失败")
			}

			// 更新出库明细
			newPickedQuantity := orderItem.PickedQuantity + reqItem.PickedQuantity
			if err := tx.Model(&orderItem).Updates(map[string]interface{}{
				"picked_quantity": newPickedQuantity,
				"location_id":     reqItem.LocationID,
			}).Error; err != nil {
				return errors.New("更新出库明细失败")
			}
		}

		// 检查是否所有订单项都已拣货完成
		var allItemsPicked bool = true
		for _, item := range outbound.Items {
			if item.PickedQuantity < item.Quantity {
				allItemsPicked = false
				break
			}
		}

		// 更新出库单状态
		outboundUpdates := map[string]interface{}{
			"pick_user_id": userID,
			"pick_time":    &now,
		}

		if allItemsPicked {
			outboundUpdates["status"] = model.StatusOutboundWaitingShipping
		}

		if err := tx.Model(&outbound).Updates(outboundUpdates).Error; err != nil {
			return errors.New("更新出库单状态失败")
		}

		return nil
	})
}

// CancelInbound 取消入库单
func (s *InventoryService) CancelInbound(id uint, userID uint) error {
	var inbound model.InboundOrder
	if err := s.db.First(&inbound, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("入库单不存在")
		}
		return err
	}

	// 只有待审核和已审核的入库单可以取消
	if inbound.Status != 1 && inbound.Status != 2 {
		return errors.New("当前状态的入库单不能取消")
	}

	// 更新入库单状态为取消
	if err := s.db.Model(&inbound).Updates(map[string]interface{}{
		"status":         5, // 已取消
		"cancel_time":    time.Now(),
		"cancel_user_id": userID,
		"updated_by":     userID,
	}).Error; err != nil {
		return err
	}

	// 记录取消入库单的日志
	s.logger.Info("入库单已取消",
		zap.String("code", inbound.Code),
		zap.Uint("id", inbound.ID),
		zap.Int("oldStatus", inbound.Status),
		zap.Int("newStatus", 5),
		zap.Uint("userID", userID))

	return nil
}

// UpdateInboundStatus 更新入库单状态
func (s *InventoryService) UpdateInboundStatus(id uint, req *request.UpdateStatusRequest, userID uint) error {
	var inbound model.InboundOrder
	if err := s.db.First(&inbound, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("入库单不存在")
		}
		return err
	}

	oldStatus := inbound.Status

	// 根据当前状态和目标状态进行验证
	switch inbound.Status {
	case model.StatusInboundWaitingReceive: // 待收货(1)
		if req.Status != strconv.Itoa(model.StatusInboundWaitingPutaway) && req.Status != strconv.Itoa(model.StatusInboundCancelled) { // 只能改为待上架或取消
			return errors.New("待收货的入库单只能改为待上架或取消")
		}
	case model.StatusInboundWaitingPutaway: // 待上架(2)
		if req.Status != strconv.Itoa(model.StatusInboundCompleted) && req.Status != strconv.Itoa(model.StatusInboundCancelled) { // 只能改为已完成或取消
			return errors.New("待上架的入库单只能改为已完成或取消")
		}
	case model.StatusInboundCompleted: // 已完成(3)
		return errors.New("已完成的入库单不能更改状态")
	case model.StatusInboundCancelled: // 已取消(0)
		return errors.New("已取消的入库单不能更改状态")
	default:
		return errors.New("当前状态的入库单不能更改状态")
	}

	// 转换请求的状态字符串为整数
	statusInt, err := strconv.Atoi(req.Status)
	if err != nil {
		return fmt.Errorf("无效的状态值: %s", req.Status)
	}

	updates := map[string]interface{}{
		"status": statusInt, // 使用转换后的整数状态
	}

	// 根据目标状态设置相应的字段
	switch statusInt {
	case model.StatusInboundCancelled: // 已取消(0)
		updates["cancel_time"] = time.Now()
		updates["cancel_user_id"] = userID
	case model.StatusInboundWaitingPutaway: // 待上架(2)
		updates["receive_time"] = time.Now()
		updates["receive_user_id"] = userID
	case model.StatusInboundCompleted: // 已完成(3)
		updates["putaway_time"] = time.Now()
		updates["putaway_user_id"] = userID
	}

	if err := s.db.Model(&inbound).Updates(updates).Error; err != nil {
		return err
	}

	// 记录状态更新日志
	s.logger.Info("入库单状态已更新",
		zap.String("code", inbound.Code),
		zap.Uint("id", inbound.ID),
		zap.Int("oldStatus", oldStatus),
		zap.Int("newStatus", statusInt),
		zap.Uint("userID", userID))

	return nil
}

// UpdateOutboundStatus 更新出库单状态
func (s *InventoryService) UpdateOutboundStatus(id uint, req *request.UpdateStatusRequest, userID uint) error {
	var outbound model.OutboundOrder
	if err := s.db.First(&outbound, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("出库单不存在")
		}
		return err
	}

	oldStatus := outbound.Status

	// 根据当前状态和目标状态进行验证
	switch outbound.Status {
	case model.StatusOutboundWaitingPicking: // 待拣货(1)
		if req.Status != strconv.Itoa(model.StatusOutboundWaitingShipping) && req.Status != strconv.Itoa(model.StatusOutboundCancelled) { // 只能改为待发货或取消
			return errors.New("待拣货的出库单只能改为待发货或取消")
		}
	case model.StatusOutboundWaitingShipping: // 待发货(2)
		if req.Status != strconv.Itoa(model.StatusOutboundCompleted) && req.Status != strconv.Itoa(model.StatusOutboundCancelled) { // 只能改为已完成或取消
			return errors.New("待发货的出库单只能改为已完成或取消")
		}
	case model.StatusOutboundCompleted: // 已完成(3)
		return errors.New("已完成的出库单不能更改状态")
	case model.StatusOutboundCancelled: // 已取消(0)
		return errors.New("已取消的出库单不能更改状态")
	default:
		return errors.New("当前状态的出库单不能更改状态")
	}

	// 转换请求的状态字符串为整数
	statusInt, err := strconv.Atoi(req.Status)
	if err != nil {
		return fmt.Errorf("无效的状态值: %s", req.Status)
	}

	updates := map[string]interface{}{
		"status":     statusInt, // 使用转换后的整数状态
		"updated_by": userID,
	}

	// 根据目标状态设置相应的字段
	switch statusInt { // 使用转换后的整数状态
	case model.StatusOutboundWaitingShipping: // 待发货(2)
		updates["pick_user_id"] = userID
		updates["pick_time"] = time.Now()
	case model.StatusOutboundCompleted: // 已完成(3)
		updates["ship_user_id"] = userID
		updates["ship_time"] = time.Now()
	case model.StatusOutboundCancelled: // 已取消(0)
		updates["cancel_user_id"] = userID
		updates["cancel_time"] = time.Now()
	}

	if err := s.db.Model(&outbound).Updates(updates).Error; err != nil {
		return err
	}

	// 记录状态更新日志
	s.logger.Info("出库单状态已更新",
		zap.String("code", outbound.Code),
		zap.Uint("id", outbound.ID),
		zap.Int("oldStatus", oldStatus),
		zap.Int("newStatus", statusInt),
		zap.Uint("userID", userID))

	return nil
}

// GetLocationInventory 获取库位库存信息
func (s *InventoryService) GetLocationInventory(locationID uint, req *request.InventoryLocationRequest) ([]*model.Inventory, int64, error) {
	// 检查库位是否存在
	var location model.Location
	if err := s.db.First(&location, locationID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, 0, errors.New("库位不存在")
		}
		return nil, 0, err
	}

	var inventories []*model.Inventory
	var total int64

	// 创建查询构建器
	db := s.db.Model(&model.Inventory{}).
		Preload("Cargo").
		Preload("Cargo.Category").
		Preload("Cargo.Supplier").
		Preload("Warehouse").
		Where("location_id = ?", locationID)

	// 添加过滤条件
	if req.CargoName != "" {
		db = db.Joins("JOIN cargos p ON p.id = inventories.cargo_id").
			Where("p.name LIKE ?", "%"+req.CargoName+"%")
	}
	if req.CargoCode != "" {
		db = db.Joins("JOIN cargos p ON p.id = inventories.cargo_id").
			Where("p.code LIKE ?", "%"+req.CargoCode+"%")
	}
	if req.BatchNo != "" {
		db = db.Joins("JOIN inventory_batches b ON b.inventory_id = inventories.id").
			Where("b.batch_no LIKE ?", "%"+req.BatchNo+"%")
	}

	// 添加排序
	if req.SortBy != "" {
		sortDir := "ASC"
		if req.SortOrder == "desc" {
			sortDir = "DESC"
		}

		switch req.SortBy {
		case "quantity":
			db = db.Order("quantity " + sortDir)
		case "cargo_name":
			db = db.Joins("JOIN cargos p ON p.id = inventories.cargo_id").
				Order("p.name " + sortDir)
		case "updated_at":
			db = db.Order("updated_at " + sortDir)
		default:
			db = db.Order("id " + sortDir)
		}
	} else {
		// 默认排序
		db = db.Order("id ASC")
	}

	// 获取总数
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 获取分页数据
	offset := (req.GetPage() - 1) * req.GetPageSize()
	if err := db.Offset(offset).Limit(req.GetPageSize()).Find(&inventories).Error; err != nil {
		return nil, 0, err
	}

	// 加载批次信息
	if err := s.loadBatchInfoForInventories(inventories); err != nil {
		s.logger.Warn("加载批次信息失败，将使用备用方法", zap.Error(err))
		s.loadBatchInfoFallback(inventories)
	}

	// 填充平铺字段，方便前端显示
	for _, inv := range inventories {
		if inv.Cargo != nil {
			inv.CargoCode = inv.Cargo.Code
			inv.CargoName = inv.Cargo.Name
			inv.Unit = inv.Cargo.Unit

			// 填充分类信息
			if inv.Cargo.Category.ID > 0 {
				// 检查 Category 是否正确加载（名称不为空）
				if inv.Cargo.Category.Name != "" {
					inv.CategoryName = inv.Cargo.Category.Name
				} else {
					// 分类信息不完整，尝试手动加载
					s.logger.Warn("分类名称为空，尝试手动加载",
						zap.Uint("cargoID", inv.Cargo.ID),
						zap.Uint("categoryID", inv.Cargo.CategoryID))

					var category model.CargoCategory
					if err := s.db.First(&category, inv.Cargo.CategoryID).Error; err == nil {
						inv.CategoryName = category.Name
						// 更新 Cargo 对象中的 Category，避免后续再次查询
						inv.Cargo.Category = category
					} else {
						s.logger.Error("手动加载分类失败",
							zap.Uint("categoryID", inv.Cargo.CategoryID),
							zap.Error(err))
					}
				}
			}

			// 填充供应商信息
			if inv.Cargo.Supplier != nil && inv.Cargo.Supplier.ID > 0 {
				if inv.Cargo.Supplier.Name != "" {
					inv.SupplierName = inv.Cargo.Supplier.Name
				} else {
					// 供应商信息不完整，尝试手动加载
					s.logger.Warn("供应商名称为空，尝试手动加载",
						zap.Uint("cargoID", inv.Cargo.ID),
						zap.Uintp("supplierID", inv.Cargo.SupplierID))

					var supplier model.Supplier
					if err := s.db.First(&supplier, *inv.Cargo.SupplierID).Error; err == nil {
						inv.SupplierName = supplier.Name
						// 更新 Cargo 对象中的 Supplier
						inv.Cargo.Supplier = &supplier
					} else {
						s.logger.Error("手动加载供应商失败",
							zap.Uintp("supplierID", inv.Cargo.SupplierID),
							zap.Error(err))
					}
				}
			}
		}

		// 填充仓库信息
		if inv.Warehouse != nil {
			inv.WarehouseName = inv.Warehouse.Name
		}

		// 填充库位信息
		if inv.Location != nil {
			inv.LocationCode = inv.Location.Code
		}
	}

	return inventories, total, nil
}

// GetPickingTasks 获取待拣货任务列表
func (s *InventoryService) GetPickingTasks() ([]*model.OutboundOrder, error) {
	var outbounds []*model.OutboundOrder

	db := s.db.Model(&model.OutboundOrder{}).
		Preload("Items").
		Preload("Items.Cargo").
		Preload("Warehouse").
		Preload("User").
		Where("status = ?", model.StatusOutboundWaitingPicking) // 待拣货状态

	// 获取数据，按创建时间降序排序
	if err := db.Order("created_at DESC").Find(&outbounds).Error; err != nil {
		return nil, err
	}

	return outbounds, nil
}

// GetShippingTasks 获取待发货任务列表
func (s *InventoryService) GetShippingTasks() ([]*model.OutboundOrder, error) {
	var outbounds []*model.OutboundOrder

	db := s.db.Model(&model.OutboundOrder{}).
		Preload("Items").
		Preload("Items.Cargo").
		Preload("Warehouse").
		Preload("User").
		Preload("PickUser").
		Where("status = ?", model.StatusOutboundWaitingShipping) // 待发货状态

	// 获取数据，按拣货时间降序排序
	if err := db.Order("pick_time DESC").Find(&outbounds).Error; err != nil {
		return nil, err
	}

	return outbounds, nil
}

// GetWarehouseProducts 获取仓库商品列表
func (s *InventoryService) GetWarehouseProducts(warehouseID uint, req *request.ProductListRequest) ([]*model.Cargo, error) {
	// 检查仓库是否存在
	var warehouse model.Warehouse
	if err := s.db.First(&warehouse, warehouseID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("仓库不存在")
		}
		return nil, err
	}

	var products []*model.Cargo

	// 创建查询构建器 - 通过库存表关联查询有库存的商品
	db := s.db.Model(&model.Cargo{}).
		Preload("Category").
		Preload("Supplier").
		Joins("JOIN inventories i ON i.cargo_id = cargos.id").
		Where("i.warehouse_id = ? AND i.quantity > 0", warehouseID).
		Group("cargos.id") // 确保每个商品只返回一次

	// 添加过滤条件
	if req.Keyword != "" {
		db = db.Where("cargos.name LIKE ? OR cargos.code LIKE ?",
			"%"+req.Keyword+"%", "%"+req.Keyword+"%")
	}
	if req.CategoryID > 0 {
		db = db.Where("cargos.category_id = ?", req.CategoryID)
	}

	// 获取数据
	if err := db.Order("cargos.name ASC").Find(&products).Error; err != nil {
		return nil, err
	}

	// 为每个产品加载库存信息
	for _, product := range products {
		var totalQty float64
		err := s.db.Model(&model.Inventory{}).
			Where("cargo_id = ? AND warehouse_id = ?", product.ID, warehouseID).
			Select("COALESCE(SUM(quantity), 0)").
			Row().Scan(&totalQty)

		if err == nil {
			product.StockQuantity = totalQty
		}
	}

	return products, nil
}

// GetProductLocations 获取产品在仓库中的库位列表
func (s *InventoryService) GetProductLocations(cargoID uint) ([]*model.Inventory, error) {
	// 检查商品是否存在
	var cargo model.Cargo
	if err := s.db.First(&cargo, cargoID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("商品不存在")
		}
		return nil, err
	}

	var inventories []*model.Inventory

	// 查询此商品在所有仓库的所有库位库存
	err := s.db.Model(&model.Inventory{}).
		Preload("Location").
		Preload("Warehouse").
		Where("cargo_id = ? AND quantity > 0", cargoID).
		Find(&inventories).Error

	if err != nil {
		return nil, err
	}

	// 加载批次信息
	if err := s.loadBatchInfoForInventories(inventories); err != nil {
		s.logger.Warn("加载批次信息失败，将使用备用方法", zap.Error(err))
		s.loadBatchInfoFallback(inventories)
	}

	return inventories, nil
}

// loadBatchInfoForInventories 为库存列表加载批次信息
func (s *InventoryService) loadBatchInfoForInventories(inventories []*model.Inventory) error {
	if len(inventories) == 0 {
		return nil
	}

	// 收集所有库存ID，用于查询批次表
	var inventoryIDs []uint
	for _, inv := range inventories {
		inventoryIDs = append(inventoryIDs, inv.ID)
	}

	// 查询所有批次信息
	var batches []*model.InventoryBatch
	if err := s.db.Where("inventory_id IN ?", inventoryIDs).Find(&batches).Error; err != nil {
		return err
	}

	// 构建批次信息映射
	batchMap := make(map[uint][]*model.InventoryBatch)
	for _, batch := range batches {
		batchMap[batch.InventoryID] = append(batchMap[batch.InventoryID], batch)
	}

	// 将批次信息填充到库存对象中
	for _, inv := range inventories {
		if batches, exists := batchMap[inv.ID]; exists && len(batches) > 0 {
			// 使用第一个批次的信息填充库存对象（简化处理）
			firstBatch := batches[0]
			inv.BatchNo = firstBatch.BatchNo
			inv.ProductionDate = firstBatch.ProductionDate
			inv.ExpiryDate = firstBatch.ExpiryDate
		}
	}

	return nil
}

// loadBatchInfoFallback 为库存列表加载批次信息的备用方法
func (s *InventoryService) loadBatchInfoFallback(inventories []*model.Inventory) {
	for _, inv := range inventories {
		// 对每个库存项单独查询批次信息
		var batch model.InventoryBatch
		if err := s.db.Where("inventory_id = ?", inv.ID).First(&batch).Error; err == nil {
			inv.BatchNo = batch.BatchNo
			inv.ProductionDate = batch.ProductionDate
			inv.ExpiryDate = batch.ExpiryDate
		} else {
			s.logger.Warn("备用方法加载批次信息失败", zap.Uint("inventoryID", inv.ID), zap.Error(err))
		}
	}
}

// GetInboundByID 获取入库单详情
func (s *InventoryService) GetInboundByID(id uint) (*model.InboundOrder, error) {
	var inbound model.InboundOrder
	if err := s.db.Preload("Items").
		Preload("Items.Cargo").
		Preload("Warehouse").
		Preload("Supplier").
		Preload("User").
		Preload("ApproveUser").
		First(&inbound, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("入库单不存在")
		}
		return nil, err
	}
	return &inbound, nil
}

// ListInbound 获取入库单列表
func (s *InventoryService) ListInbound(req *request.InboundListRequest) ([]*model.InboundOrder, int64, error) {
	var inbounds []*model.InboundOrder
	var total int64

	db := s.db.Model(&model.InboundOrder{}).
		Preload("Warehouse").
		Preload("Supplier").
		Preload("User")

	// 添加查询条件
	if req.Keyword != "" {
		db = db.Where("code LIKE ? OR order_no LIKE ?", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
	}
	if req.WarehouseID > 0 {
		db = db.Where("warehouse_id = ?", req.WarehouseID)
	}
	if req.Status > 0 {
		db = db.Where("status = ?", req.Status)
	}
	if req.StartTime != "" {
		db = db.Where("created_at >= ?", req.StartTime)
	}
	if req.EndTime != "" {
		db = db.Where("created_at <= ?", req.EndTime)
	}

	// 获取总数
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 获取分页数据
	offset := (req.GetPage() - 1) * req.GetPageSize()
	if err := db.Order("created_at DESC").Offset(offset).Limit(req.GetPageSize()).Find(&inbounds).Error; err != nil {
		return nil, 0, err
	}

	return inbounds, total, nil
}

// GetInventoryHistory 获取库存历史记录
func (s *InventoryService) GetInventoryHistory(req *request.InventoryHistoryRequest) ([]*model.InventoryLog, int64, error) {
	var logs []*model.InventoryLog
	var total int64

	db := s.db.Model(&model.InventoryLog{}).
		Preload("Cargo").
		Preload("Warehouse").
		Preload("Location").
		Preload("Operator")

	// 添加过滤条件
	if req.CargoID > 0 {
		db = db.Where("cargo_id = ?", req.CargoID)
	}
	if req.WarehouseID > 0 {
		db = db.Where("warehouse_id = ?", req.WarehouseID)
	}
	if req.LocationID > 0 {
		db = db.Where("location_id = ?", req.LocationID)
	}
	if req.Type != "" {
		db = db.Where("type = ?", req.Type)
	}
	if req.StartDate != "" {
		db = db.Where("created_at >= ?", req.StartDate)
	}
	if req.EndDate != "" {
		db = db.Where("created_at <= ?", req.EndDate)
	}

	// 获取总数
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 获取分页数据
	offset := (req.GetPage() - 1) * req.GetPageSize()
	if err := db.Order("created_at DESC").Offset(offset).Limit(req.GetPageSize()).Find(&logs).Error; err != nil {
		return nil, 0, err
	}

	return logs, total, nil
}

// ReceiveOrder 处理收货操作
func (s *InventoryService) ReceiveOrder(orderID uint, req *request.ReceiveRequest, userID uint) error {
	var inbound model.InboundOrder
	if err := s.db.Preload("Items").
		Preload("Items.Cargo").
		Preload("Warehouse").
		First(&inbound, orderID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("入库单不存在")
		}
		return err
	}

	// 检查状态是否为待收货
	if inbound.Status != model.StatusInboundWaitingReceive {
		return errors.New("入库单状态不是待收货")
	}

	// 将请求中的items映射到map中，方便查找
	reqItemMap := make(map[uint]request.ReceiveItem)
	for _, item := range req.Items {
		reqItemMap[item.OrderItemID] = item
	}

	// 开启事务
	return s.db.Transaction(func(tx *gorm.DB) error {
		now := time.Now()

		// 更新入库单明细
		for _, orderItem := range inbound.Items {
			reqItem, exists := reqItemMap[orderItem.ID]
			if !exists {
				continue // 忽略不在请求中的明细
			}

			// 更新明细的收货数量
			if err := tx.Model(&orderItem).Update("received_quantity", reqItem.ReceivedQuantity).Error; err != nil {
				return err
			}

			// 如果有批次信息，创建批次
			if reqItem.BatchNo != "" {
				// 预留批次信息的创建逻辑
			}
		}

		// 更新入库单状态 (如果不需要保持状态)
		newStatus := model.StatusInboundWaitingPutaway
		if req.PreserveStatus {
			newStatus = inbound.Status
		}

		updates := map[string]interface{}{
			"receive_time":    now,
			"receive_user_id": userID,
			"status":          newStatus,
			"updated_by":      userID,
		}

		if err := tx.Model(&inbound).Updates(updates).Error; err != nil {
			return err
		}

		return nil
	})
}

// PutawayOrder 处理上架操作
func (s *InventoryService) PutawayOrder(orderID uint, req *request.PutawayRequest, userID uint) error {
	var inbound model.InboundOrder
	if err := s.db.Preload("Items").
		Preload("Items.Cargo").
		Preload("Warehouse").
		First(&inbound, orderID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("入库单不存在")
		}
		return err
	}

	// 检查状态是否为待上架
	if inbound.Status != model.StatusInboundWaitingPutaway {
		return errors.New("入库单状态不是待上架")
	}

	// 将请求中的items映射到map中，方便查找
	reqItemMap := make(map[uint]request.PutawayItem)
	for _, item := range req.Items {
		reqItemMap[item.OrderItemID] = item
	}

	// 开启事务
	return s.db.Transaction(func(tx *gorm.DB) error {
		now := time.Now()
		allItemsPutaway := true

		// 更新入库单明细
		for _, orderItem := range inbound.Items {
			reqItem, exists := reqItemMap[orderItem.ID]
			if !exists {
				// 如果有任何明细未上架完成，不能将状态改为完成
				if orderItem.PutawayQuantity < orderItem.ReceivedQuantity {
					allItemsPutaway = false
				}
				continue // 忽略不在请求中的明细
			}

			// 检查库位是否存在
			var location model.Location
			if err := tx.Where("id = ?", reqItem.LocationID).First(&location).Error; err != nil {
				if errors.Is(err, gorm.ErrRecordNotFound) {
					return errors.New("指定的库位不存在")
				}
				return err
			}

			// 计算新的已上架数量
			newPutawayQty := orderItem.PutawayQuantity + reqItem.PutawayQuantity

			// 如果新的已上架数量超过了已收货数量，返回错误
			if newPutawayQty > orderItem.ReceivedQuantity {
				return fmt.Errorf("上架数量 %.2f 超过了已收货数量 %.2f", newPutawayQty, orderItem.ReceivedQuantity)
			}

			// 更新明细的上架数量
			if err := tx.Model(&orderItem).Update("putaway_quantity", newPutawayQty).Error; err != nil {
				return err
			}

			// 查找或创建库存记录
			var inventory model.Inventory
			result := tx.Where("cargo_id = ? AND warehouse_id = ? AND location_id = ?",
				orderItem.CargoID, inbound.WarehouseID, reqItem.LocationID).
				First(&inventory)

			if result.Error != nil {
				if errors.Is(result.Error, gorm.ErrRecordNotFound) {
					// 创建新的库存记录
					inventory = model.Inventory{
						CargoID:     orderItem.CargoID,
						WarehouseID: inbound.WarehouseID,
						LocationID:  reqItem.LocationID,
						Quantity:    reqItem.PutawayQuantity,
						Status:      1, // 正常
					}
					if err := tx.Create(&inventory).Error; err != nil {
						return err
					}
				} else {
					return result.Error
				}
			} else {
				// 更新现有库存
				beforeStock := inventory.Quantity
				afterStock := beforeStock + reqItem.PutawayQuantity
				if err := tx.Model(&inventory).Update("quantity", afterStock).Error; err != nil {
					return err
				}

				// 创建库存日志
				log := &model.InventoryLog{
					CargoID:     orderItem.CargoID,
					WarehouseID: inbound.WarehouseID,
					LocationID:  reqItem.LocationID,
					Type:        "in",
					Quantity:    int(reqItem.PutawayQuantity),
					BeforeStock: int(beforeStock),
					AfterStock:  int(afterStock),
					OrderType:   "inbound",
					OrderID:     inbound.ID,
					OperatorID:  userID,
					Remark:      fmt.Sprintf("入库单上架: %s", inbound.Code),
				}
				if err := tx.Create(log).Error; err != nil {
					return err
				}
			}

			// 检查是否所有明细都已上架完成
			if newPutawayQty < orderItem.ReceivedQuantity {
				allItemsPutaway = false
			}
		}

		// 更新入库单状态
		updates := map[string]interface{}{
			"updated_by": userID,
		}

		// 如果所有明细都已上架完成，将状态更新为已完成
		if allItemsPutaway {
			updates["status"] = model.StatusInboundCompleted
			updates["putaway_time"] = now
			updates["putaway_user_id"] = userID
		}

		if err := tx.Model(&inbound).Updates(updates).Error; err != nil {
			return err
		}

		return nil
	})
}

// ShipOrder 处理出库单发货操作
func (s *InventoryService) ShipOrder(orderID uint, req *request.ShipRequest, userID uint) error {
	var outbound model.OutboundOrder
	if err := s.db.Preload("Items").
		Preload("Items.Cargo").
		Preload("Warehouse").
		First(&outbound, orderID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("出库单不存在")
		}
		return err
	}

	// 检查状态是否为待发货
	if outbound.Status != model.StatusOutboundWaitingShipping {
		return errors.New("出库单状态不是待发货")
	}

	// 开启事务
	return s.db.Transaction(func(tx *gorm.DB) error {
		now := time.Now()
		shipTime := now
		if req.ShippedTime != nil {
			shipTime = *req.ShippedTime
		}

		// 更新出库单信息
		updates := map[string]interface{}{
			"status":       model.StatusOutboundCompleted,
			"ship_time":    shipTime,
			"ship_user_id": userID,
			"updated_by":   userID,
		}

		if req.TrackingNumber != "" {
			updates["tracking_number"] = req.TrackingNumber
		}
		if req.Carrier != "" {
			updates["carrier"] = req.Carrier
		}
		if req.ShippingCost != nil {
			updates["shipping_cost"] = *req.ShippingCost
		}

		if err := tx.Model(&outbound).Updates(updates).Error; err != nil {
			return err
		}

		return nil
	})
}

// GetOutboundStatistics 获取出库单统计信息
func (s *InventoryService) GetOutboundStatistics() (map[string]int64, error) {
	var waitingPickCount, waitingShipCount int64

	// 统计待拣货数量
	if err := s.db.Model(&model.OutboundOrder{}).
		Where("status = ?", model.StatusOutboundWaitingPicking).
		Count(&waitingPickCount).Error; err != nil {
		return nil, err
	}

	// 统计待发货数量
	if err := s.db.Model(&model.OutboundOrder{}).
		Where("status = ?", model.StatusOutboundWaitingShipping).
		Count(&waitingShipCount).Error; err != nil {
		return nil, err
	}

	return map[string]int64{
		"waiting_pick": waitingPickCount,
		"waiting_ship": waitingShipCount,
	}, nil
}
